package pzc.sort;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import pzc.reflect.introspection.IntrospectionUtils;
import pzc.sort.SortItem.SortDestination;
import pzc.sort.SortItem.SortType;


public class CommonComparator<T> implements Comparator<T> {
	private List<SortItem> sortItemList = new ArrayList<SortItem>();

	public final void addSortItem(String name, SortDestination sortDest) {
		this.sortItemList.add(new SortItem(name, null, sortDest));
	}

	public final void addSortItem(String name, SortType sortType, SortDestination sortDest) {
		this.sortItemList.add(new SortItem(name, sortType, sortDest));
	}

	// implements the Comparator#compare
	public final int compare(Object o1, Object o2) {
		int flag = 0;
		if (this.sortItemList != null && this.sortItemList.size() > 0) {
			for (int i = 0; i < this.sortItemList.size(); i++) {
				SortItem sortItem = this.sortItemList.get(i);
				String itemName = sortItem.getItemName();
				SortType sortType = sortItem.getSortType();
				SortDestination sortDest = sortItem.getSortDest();

				Object value_1 = getData(o1, itemName);
				Object value_2 = getData(o2, itemName);

				if (sortDest == SortDestination.ASC) {
					flag = this.realCompare(sortType, value_1, value_2);
				} else {
					flag = this.realCompare(sortType, value_2, value_1);
				}

				if (flag != 0) {
					break;
				}
			}
		}
		return flag;
	}

	private int realCompare(SortType sortType, Object val1, Object val2) {
		int flag = 0;
		if (val1 == null && val2 == null) {
			flag = 0;
		} else if (val1 != null && val2 == null) {
			flag = 1;
		} else if (val1 == null && val2 != null) {
			flag = -1;
		} else {
			/* val1 != null && val2 != null */
			if (val1 instanceof Comparable) {
				flag = ((Comparable) val1).compareTo((Comparable) val2);
			} else if (val1 instanceof Iterable) {
				// Iterableは対象外:List,Set
				/*
				Iterator it1 = ((Iterable)val1).iterator();
				Iterator it2 = ((Iterable)val2).iterator();
				while(flag == 0){
					if(it1.hasNext() && it2.hasNext()){
						flag = compare(it1.next(),it2.next());
					}else if(it1.hasNext() && it2.hasNext() == false){
						flag = 1;
					}else if(it1.hasNext() == false && it2.hasNext()){
						flag = -1;
					}
				}
				*/
			} else if (val1 instanceof Map) {
				// Mapは対象外
				/*
				Map map1 = (Map)val1;
				Map map2 = (Map)val2;
				*/
			} else {
				// override method
				flag = extCompare(val1, val2);
			}
		}
		return flag;
	}

	// can be overrided, return value (-1, 0, 1)
	public int extCompare(Object val1, Object val2) {
		// default value is 0 (equals)
		return 0;
	}

	// can be overrided, return value must be Object
	public Object getData(Object o, String itemName) {
		Object ret = null;
		try {
			ret = IntrospectionUtils.getInstanceProperty(o, itemName);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return ret;
	}

}
